package com.ruoyi.data.opc;

import com.google.common.collect.ImmutableList;
import com.ruoyi.constant.ERPConstant;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.data.opc.config.Client;
import com.ruoyi.machine.advanced.alarm.domain.MachineAlarm;
import com.ruoyi.machine.advanced.alarm.service.IMachineAlarmService;
import com.ruoyi.machine.advanced.status.domain.Status;
import com.ruoyi.machine.advanced.status.service.IStatusService;
import com.ruoyi.machine.base.device.domain.Device;
import com.ruoyi.machine.base.device.service.IDeviceService;
import com.ruoyi.produce.base.shift.service.IProduceShiftInfoService;
import com.ruoyi.produce.process.datacollection.domain.DataCollection;
import com.ruoyi.produce.process.datacollection.service.IDataCollectionService;
import com.ruoyi.produce.process.parameter.domain.ProcessParameter;
import com.ruoyi.produce.process.parameter.service.IProcessParameterService;
import com.ruoyi.produce.process.scheduling.domain.Scheduling;
import com.ruoyi.produce.process.scheduling.service.ISchedulingService;
import org.eclipse.milo.opcua.sdk.client.OpcUaClient;
import org.eclipse.milo.opcua.stack.core.types.builtin.DataValue;
import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId;
import org.eclipse.milo.opcua.stack.core.types.enumerated.TimestampsToReturn;

import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

public class OpcUAClientRunner {
    /**
     * 数据采集并且写入数据库中
     */
    public static void collectData(IStatusService statusService, ISchedulingService schedulingService, IDataCollectionService dataCollectionService, IProduceShiftInfoService shiftInfoService, IDeviceService deviceService, IMachineAlarmService machineAlarmService, IProcessParameterService processParameterService) {
        List<Device> deviceList = deviceService.selectAllOpcMachine();//查询到所有opc通信协议ip的设备
//        OpcUAClientUtils utils = new OpcUAClientUtils();
        for (int i = 0; i < deviceList.size(); i++) {
            OpcUaClient opcUaClient = null;
            Status status = statusService.selectStatusById(deviceList.get(i).getMachineId()); //设备状态
            try {
                //读产量
                // 创建OPC UA客户端
                opcUaClient = Client.createClient(deviceList.get(i).getMachineIp());
                opcUaClient.connect().get(); //建立连接

                //处理通信状态
                status.setCommunicateStatus(ERPConstant.COMMON_SUCCEED); //通信成功
                statusService.updateStatus(status); //更新机器状态

                // 读节点数据
                NodeId nodeId_Tag1 = new NodeId(1, 1125380); //模穴数
                NodeId nodeId_Tag2 = new NodeId(1, 1117188); //开模序号
                NodeId nodeId_Tag3 = new NodeId(1, 1117790); //警报状态
                NodeId nodeId_Tag4 = new NodeId(1, 123461); //警报信息1
                NodeId nodeId_Tag5 = new NodeId(1, 123464); //警报信息2
                NodeId nodeId_Tag6 = new NodeId(1, 123467); //警报信息3
                NodeId nodeId_Tag7 = new NodeId(1, 1117792); //工作状态

                NodeId nodeId_Tag8 = new NodeId(1, 135334536); //温度1
                NodeId nodeId_Tag9 = new NodeId(1, 135334537); //温度2
                NodeId nodeId_Tag10 = new NodeId(1, 135334538); //温度3
                NodeId nodeId_Tag11 = new NodeId(1, 135334539); //温度4
                NodeId nodeId_Tag12 = new NodeId(1, 50603560); //射出压力1
                NodeId nodeId_Tag13 = new NodeId(1, 50603561); //射出压力2
                NodeId nodeId_Tag14 = new NodeId(1, 50603562); //射出压力3
                NodeId nodeId_Tag15 = new NodeId(1, 50603563); //射出压力4
                NodeId nodeId_Tag16 = new NodeId(1, 50602660); //射出速度1
                NodeId nodeId_Tag17 = new NodeId(1, 50602661); //射出速度2
                NodeId nodeId_Tag18 = new NodeId(1, 50602662); //射出速度3
                NodeId nodeId_Tag19 = new NodeId(1, 50602663); //射出速度4
                List<NodeId> nodeIds = ImmutableList.of(
                        nodeId_Tag1,
                        nodeId_Tag2,
                        nodeId_Tag3,
                        nodeId_Tag4,
                        nodeId_Tag5,
                        nodeId_Tag6,
                        nodeId_Tag7,
                        nodeId_Tag8, nodeId_Tag9, nodeId_Tag10, nodeId_Tag11,
                        nodeId_Tag12, nodeId_Tag13, nodeId_Tag14, nodeId_Tag15,
                        nodeId_Tag16, nodeId_Tag17, nodeId_Tag18, nodeId_Tag19);
                CompletableFuture<List<DataValue>> future = opcUaClient.readValues(0.0, TimestampsToReturn.Both, nodeIds);
                List<DataValue> valueList = future.get();
                System.out.println("设备" + deviceList.get(i).getMachineId() + "数据读取成功");


                // 处理工作状态
                DataValue workStatusValue = valueList.get(6);
                int workStatus = Integer.parseInt(workStatusValue.getValue().getValue().toString());
                //更新机器状态
                if (workStatus != 0) {
                    // 说明在工作
                    status.setWorkStatus(ERPConstant.COMMON_SUCCEED);
                } else {
                    status.setWorkStatus(ERPConstant.COMMON_FAIL);
                }
                statusService.updateStatus(status); //更新机器状态

                // 处理产量
                DataValue moldHoleValue = valueList.get(0); //模穴数
                DataValue openModulusValue = valueList.get(1); //开模序号
                int moldHoleNumber = Integer.parseInt(moldHoleValue.getValue().getValue().toString()); //模穴数
//                System.out.println("模穴数" + moldHoleNumber);
                int openModulus = Integer.parseInt(openModulusValue.getValue().getValue().toString()); //开模序号
//                System.out.println("开模序号" + openModulus);
                int output = moldHoleNumber * openModulus; //产量
//                System.out.println("产量" + output);
                // 处理工艺参数
                DataValue temperatureValue1 = valueList.get(7); //温度1
                double temperature1 = Double.parseDouble(temperatureValue1.getValue().getValue().toString());
                DataValue temperatureValue2 = valueList.get(8); //温度2
                double temperature2 = Double.parseDouble(temperatureValue2.getValue().getValue().toString());
                DataValue temperatureValue3 = valueList.get(9); //温度3
                double temperature3 = Double.parseDouble(temperatureValue3.getValue().getValue().toString());
                DataValue temperatureValue4 = valueList.get(10); //温度4
                double temperature4 = Double.parseDouble(temperatureValue4.getValue().getValue().toString());
                DataValue pressureValue1 = valueList.get(11); //射出压力1
                double pressure1 = Double.parseDouble(pressureValue1.getValue().getValue().toString());
                DataValue pressureValue2 = valueList.get(12); //射出压力2
                double pressure2 = Double.parseDouble(pressureValue2.getValue().getValue().toString());
                DataValue pressureValue3 = valueList.get(13); //射出压力3
                double pressure3 = Double.parseDouble(pressureValue3.getValue().getValue().toString());
                DataValue pressureValue4 = valueList.get(14); //射出压力4
                double pressure4 = Double.parseDouble(pressureValue4.getValue().getValue().toString());
                DataValue speedValue1 = valueList.get(15); //射出速度1
                double speed1 = Double.parseDouble(speedValue1.getValue().getValue().toString());
                DataValue speedValue2 = valueList.get(16); //射出速度2
                double speed2 = Double.parseDouble(speedValue2.getValue().getValue().toString());
                DataValue speedValue3 = valueList.get(17); //射出速度3
                double speed3 = Double.parseDouble(speedValue3.getValue().getValue().toString());
                DataValue speedValue4 = valueList.get(18); //射出速度4
                double speed4 = Double.parseDouble(speedValue4.getValue().getValue().toString());

                // 产量存数据库
                List<Scheduling> schedulingList = schedulingService.selectSchedulingById(shiftInfoService.createShiftInfoId(), deviceList.get(i).getMachineId());//查询出加工单和员工等信息
                if (schedulingList.size() != 0) {
                    // 找到排产状态为正在进行的设备
                    Scheduling scheduling = null;
                    for (Scheduling item : schedulingList) {
                        if (item.getCompletedStatus().equals("1")) {
                            scheduling = item;
                        }
                    }
//                    Scheduling scheduling = schedulingList.get(0);
                    // 有排产记录的机器
                    DataCollection dataCollection = dataCollectionService.selectDataCollectionById(shiftInfoService.createShiftInfoId(), deviceList.get(i).getMachineId(), scheduling.getWorkSheetId());
                    if (StringUtils.isNotNull(dataCollection)) {
                        // 存在，更新
                        dataCollection.setUpdateProduction(output);
                        dataCollection.setProduceNumber(output - dataCollection.getInitialProduction()); // 更新数量 - 初始数量 = 产量
                        dataCollectionService.updateDataCollection(dataCollection);
//                        System.out.println("更新成功, 更新对象" + dataCollection);
                    } else {
                        // 新增
                        DataCollection collection = new DataCollection(shiftInfoService.createShiftInfoId(), deviceList.get(i).getMachineId(), scheduling.getWorkSheetId(), scheduling.getStaffId(), output);
                        collection.setUpdateProduction(output); //更新数值先默认为初始数值
                        dataCollectionService.insertDataCollection(collection);
//                        System.out.println("新增成功");
                    }

                    ProcessParameter processParameter = processParameterService.selectProcessParameterById(scheduling.getWorkSheetId());
                    if (StringUtils.isNotNull(processParameter)) {
                        processParameter.setTemperature1(temperature1);
                        processParameter.setTemperature2(temperature2);
                        processParameter.setTemperature3(temperature3);
                        processParameter.setTemperature4(temperature4);
                        processParameter.setPressure1(pressure1);
                        processParameter.setPressure2(pressure2);
                        processParameter.setPressure3(pressure3);
                        processParameter.setPressure4(pressure4);
                        processParameter.setSpeed1(speed1);
                        processParameter.setSpeed2(speed2);
                        processParameter.setSpeed3(speed3);
                        processParameter.setSpeed4(speed4);
                        // 更新
                        processParameterService.updateProcessParameter(processParameter);
                        System.out.println("更新成功");
                    } else {
                        // 新增
                        ProcessParameter parameter = new ProcessParameter(scheduling.getWorkSheetId(), deviceList.get(i).getMachineId(), temperature1, temperature2, temperature3, temperature4, pressure1, pressure2, pressure3, pressure4, speed1, speed2, speed3, speed4);
                        processParameterService.insertProcessParameter(parameter);
                        System.out.println("新增成功");
                    }
                }



                //处理警报状态
                DataValue alarmStatusValue = valueList.get(2); //警报状态
                int alarmStatus = Integer.parseInt(alarmStatusValue.getValue().getValue().toString()); //开模序号
                if (alarmStatus == 0) {
                    // 无警报
                    status.setAlarmStatus(ERPConstant.COMMON_NO);
                    statusService.updateStatus(status); //更新机器状态
                } else {
                    // 有警报
                    status.setAlarmStatus(ERPConstant.COMMON_YES);
                    statusService.updateStatus(status); //更新机器状态
                    System.out.println("设备" + deviceList.get(i).getMachineId() + "警报预警");
                    // 找到哪个警报报警
                    String alarmContent = "警报信息暂存";
//                    DataValue alarmContentValue1 = valueList.get(3); //警报1
//                    DataValue alarmContentValue2 = valueList.get(4); //警报2
//                    DataValue alarmContentValue3 = valueList.get(5); //警报3

                    // 找到报警信息
                    // 存入警报记录模块
//                    MachineAlarm machineAlarm = new MachineAlarm(deviceList.get(i).getMachineId(), alarmContent);
//                    machineAlarmService.insertMachineAlarm(machineAlarm); //新增警报记录
                }
            }
            catch (InterruptedException e) {
                status.setCommunicateStatus(ERPConstant.COMMON_FAIL); //通信建立失败
                status.setWorkStatus(ERPConstant.COMMON_FAIL); //工作状态失败
                statusService.updateStatus(status); //更新机器状态
                System.out.println("设备" + deviceList.get(i).getMachineId() + "连接异常111");
                e.printStackTrace();
            }
            catch (ExecutionException e) {
                status.setCommunicateStatus(ERPConstant.COMMON_FAIL); //通信建立失败
                status.setWorkStatus(ERPConstant.COMMON_UNKNOWN); //工作状态未知
                status.setAlarmStatus(ERPConstant.COMMON_UNKNOWN); //警报状态未知
                statusService.updateStatus(status); //更新机器状态
                System.out.println("设备" + deviceList.get(i).getMachineId() + "连接异常222");
                e.printStackTrace();
            }catch (Exception e) {
                status.setCommunicateStatus(ERPConstant.COMMON_FAIL); //通信建立失败
                status.setWorkStatus(ERPConstant.COMMON_UNKNOWN); //工作状态未知
                status.setAlarmStatus(ERPConstant.COMMON_UNKNOWN); //警报状态未知
                statusService.updateStatus(status); //更新机器状态
                System.out.println("设备" + deviceList.get(i).getMachineId() + "创建客户端异常");
                e.printStackTrace();
            }
            finally {
                if (opcUaClient != null) {
                    opcUaClient.disconnect();
                }
            }
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
